﻿using System.Linq;
using System.Xml.Linq;

using Microsoft.WowAddonStudio.Lua.Model;

using NUnit.Framework;
using System.Diagnostics;

namespace Microsoft.WowAddonStudio.Lua.Tests.Model
{
    [TestFixture]
    public class XmlDocumentationSerializerTest : DocumentationTestBase
    {
        [Test]
        public void WowApiTest()
        {
            var wowApiDocumentation = this.DeserializeDocumentation(wowApiRelativePath);

            Assert.AreEqual(2, wowApiDocumentation.Functions.Count());
            Assert.AreEqual(1, wowApiDocumentation.Variables.Count());

            var unitExistsFunction = wowApiDocumentation.Resolve<Function>("UnitExists");

            Assert.IsNotNull(unitExistsFunction);
            Assert.AreEqual(1, unitExistsFunction.Parameters.Length);
            Assert.IsTrue(unitExistsFunction.Parameters[0] is ParameterChoice);
            Assert.AreEqual(2, ((ParameterChoice)unitExistsFunction.Parameters[0]).Choices.Length);
            Assert.AreEqual(1, unitExistsFunction.Returns.Length);
        }

        [Test]
        public void WidgetApiTest()
        {
            var widgetApiDocumentation = this.DeserializeDocumentation(widgetApiRelativePath);

            Assert.AreEqual(3, widgetApiDocumentation.Tables.Count());

            var uiObjectTable = widgetApiDocumentation.Resolve<Table>("UIObject");
            var regionTable = widgetApiDocumentation.Resolve<Table>("Region");
            var frameTable = widgetApiDocumentation.Resolve<Table>("Frame");

            Assert.IsNotNull(uiObjectTable);
            Assert.IsNotNull(regionTable);
            Assert.IsNotNull(frameTable);

            Assert.AreEqual(1, uiObjectTable.Declarations.Count);
            Assert.AreEqual(2, regionTable.Declarations.Count);
            Assert.AreEqual(3, frameTable.Declarations.Count);
        }

        [Test]
        public void StringApiTest()
        {
            var stringDocumentation = this.DeserializeDocumentation(stringRelativePath);

            var formatMethod = stringDocumentation.Resolve<Table>("string").Resolve<Method>("format");

            Assert.IsNotNull(formatMethod);
            Assert.IsTrue(formatMethod.Variadic);
            Assert.AreEqual(2, formatMethod.Parameters.Length);
            Assert.AreEqual(1, formatMethod.Returns.Length);
        }

        [Test]
        public void MultipleDocumentationTest()
        {
            var documentation = new Documentation();

            // Merge the documentation together
            documentation.Merge(this.DeserializeDocumentation(stringRelativePath));
            documentation.Merge(this.DeserializeDocumentation(widgetApiRelativePath));
            documentation.Merge(this.DeserializeDocumentation(wowApiRelativePath));

            Assert.AreEqual(7, documentation.Declarations.Count());
        }

        [Test]
        public void SerializeDocumentationTest()
        {
            var documentation = new Documentation();

            var xmlDocumentation = this.SerializeDocumentation(documentation);

            // Assert that a valid XML string was returned that can be parsed
            Assert.IsNotNull(xmlDocumentation);
            Assert.AreNotEqual(0, xmlDocumentation.Length);
            Assert.IsNotNull(XDocument.Parse(xmlDocumentation));

            // Assert that the XML string can be deserialized into Documentation
            this.AssertDocumentationString(xmlDocumentation);
        }

        [Test]
        public void SerializeVariableTest()
        {
            var documentation = new Documentation();

            documentation.Add(new Variable
                              {
                                  Name = "foo",
                                  Type = LuaType.Number
                              });

            var xmlDocumentation = this.SerializeDocumentation(documentation);

            // Assert that a valid XML string was returned that can be parsed
            Assert.IsNotNull(xmlDocumentation);
            Assert.AreNotEqual(0, xmlDocumentation.Length);

            // Assert that the XML string can be deserialized into Documentation
            this.AssertDocumentationString(xmlDocumentation);

        }

        [Test]
        public void SerializeFunctionTest()
        {
            var documentation = new Documentation();

            documentation.Add(new Function
            {
                Name = "foo",
                Summary = "Just a foo function."
            });

            var xmlDocumentation = this.SerializeDocumentation(documentation);

            // Assert that a valid XML string was returned that can be parsed
            Assert.IsNotNull(xmlDocumentation);
            Assert.AreNotEqual(0, xmlDocumentation.Length);

            // Assert that the XML string can be deserialized into Documentation
            this.AssertDocumentationString(xmlDocumentation);
        }
    }
}